1 Tekrarlanabilir Analiz ve Rapor


1.2 Replication Crisis Excel Version


2 RStudio ile proje oluştur


3 R Notebook

3.1 R Notebook dökümanı oluşturma


3.2 R Notebook’tan html, pdf ve word oluşturma


3.3 RNotebook vs RMarkdown

https://youtu.be/zNzZ1PfUDNk


4 R Markdown

4.1 Hem kendi kodları hem de html kodları yazılabilir

https://rmarkdown.rstudio.com

What is R Markdown? from RStudio, Inc. on Vimeo.


4.2 R Markdown: The Definitive Guide

https://bookdown.org/yihui/rmarkdown/


4.4 Remedy Package


4.4.1 Remedy


4.6 Render Markdown via code

inside R

markdown::markdownToHTML('markdown_example.md', 
'markdown_example.html')

command line

R -e "markdown::markdownToHTML('markdown_example.md',
'markdown_example.html')"

4.7 pandoc Rstudio integration

command line

export PATH=$PATH:/Applications/RStudio.app/Contents/MacOS/pandoc
R -e "rmarkdown::render('markdown_example.md')"

5 RMarkdown chunk içinde R kodlarını çalıştırma

{r, results='asis'}
 iris %>%
  tibble::as_tibble() %>%
  details::details(summary = 'tibble')

6 Metin arasında R kodlarını çalıştırma


7 Chunk Options

7.1 Global Options

{r global_options 1, include=FALSE}
knitr::opts_chunk$set(fig.width = 12,
                      fig.height = 8,
                      fig.path = 'Figs/',
                      echo = FALSE,
                      warning = FALSE,
                      message = FALSE,
                      error = FALSE,
                      eval = TRUE,
                      tidy = TRUE,
                      comment = NA)

7.2 Other Code Languages


8 R Markdown kod örneği

{r}
data("cancer")
cancer
foreign::write.foreign(df = cancer,
                        datafile = "data/cancer.sav",
                        codefile = "data/cancer.spo",
                        package = "SPSS"
                        )

9 R Markdown Paket Çağırma 📦

{r}
suppressPackageStartupMessages(library("tidyverse"))
suppressPackageStartupMessages(library("survival"))

9.1 Sık kullandığım paketler 📦

{tidyverse} {tidylog}

{lubridate} {janitor}

{readxl} {foreign}

{summarytools} {ggstatsplot} {tangram} {finalfit} {psycho} {jmv}

{survival} {survminer}

{report} {kableExtra}


10 R Markdown Veri Yükleme SPSS


11 R Markdown Veri Yükleme Excel


12 Veri Görüntüleme

{r}
View(mydata)
glimpse(mydata)

13 Veri Düzenleme

{r}
mydata <- janitor::clean_names(mydata)
{r}
mydata$sontarih <- janitor::excel_numeric_to_date(
  as.numeric(mydata$olum_tarihi)
  )

14 Recode

{r}
mydata$Outcome <- "Dead"
mydata$Outcome[mydata$olum_tarihi == "yok"] <- "Alive"
{r}
## Recoding mydata$cinsiyet into mydata$Cinsiyet
mydata$Cinsiyet <- recode(mydata$cinsiyet,
               "K" = "Kadin",
               "E" = "Erkek")
mydata$Cinsiyet <- factor(mydata$Cinsiyet)

15 Recode regular expression

{r recode TNM stage}
#pT2N0Mx -> 2
mydata$Tstage <- stringr::str_match(
  mydata$patolojik_evre, 
  paste('(.+)', "N", sep=''))[,2]
)

16 Recode regular expression case_when

{r recode TNM2}
mydata <- mydata %>% 
    mutate(
        T_stage = case_when(
            grepl(pattern = "T1", x = .$Tstage) == TRUE ~ "T1",
            grepl(pattern = "T2", x = .$Tstage) == TRUE ~ "T2",
            grepl(pattern = "T3", x = .$Tstage) == TRUE ~ "T3",
            grepl(pattern = "T4", x = .$Tstage) == TRUE ~ "T4",
            TRUE ~ "Tx"
        )
    )

17 Recode regular expression case_when

{r}
mydata <- mydata %>% 
    mutate(
TumorPDL1gr1 = case_when(
        t_pdl1 < 1 ~ "kucuk1",
        t_pdl1 >= 1 ~ "buyukesit1"
    )
    )

18 R Markdown Tanımlayıcı İstatistikler

{r}
library(summarytools)
view(dfSummary(colon_s))

A beginner kit for #rstats The Landscape of R Packages for Automated Exploratory Data Analysis https://journal.r-project.org/archive/2019/RJ-2019-033/

@article{RJ-2019-033, author = {Mateusz Staniak and Przemysław Biecek}, title = {{The Landscape of R Packages for Automated Exploratory Data Analysis}}, year = {2019}, journal = {{The R Journal}}, doi = {10.32614/RJ-2019-033}, url = {https://journal.r-project.org/archive/2019/RJ-2019-033/index.html} }


18.1 Table One

{r, results='asis'}
# cat(names(mydata), sep = " + \n")
library(arsenal)
tab1 <- tableby(~ Cinsiyet + 
Yas + 
TumorYerlesimi
                ,
                data = mydata)
summary(tab1)

18.3 Kategorik Veriler

{r}
mydata %>% 
  janitor::tabyl(Categorical) %>%
  adorn_pct_formatting(rounding = 'half up',
                       digits = 1) %>%
  knitr::kable()
{r crosstable}
mydata %>%
    summary_factorlist(dependent = dependent, 
                       explanatory = explanatory,
                       total_col = TRUE,
                       p = TRUE,
                       add_dependent_label = TRUE) -> table
knitr::kable(table, row.names = FALSE, align = c('l', 'l', 'r', 'r', 'r'))

18.4 Kategorik Veriler için Grafikler

{r ggstatplot, layout='l-page'}
mydata %>% 
    ggstatsplot::ggbarstats(data = .,
                            main = Categorical_variable,
                            condition =  dependent_variable
                            )

18.5 Continious Variables

{r}
mydata %>% 
jmv::descriptives(
    data = .,
    vars = c(yas),
    hist = TRUE,
    dens = TRUE,
    box = TRUE,
    violin = TRUE,
    dot = TRUE,
    mode = TRUE,
    sd = TRUE,
    variance = TRUE,
    skew = TRUE,
    kurt = TRUE,
    quart = TRUE)

19 R Markdown örneği Çapraz Tablolar

{r crosstable}
library(finalfit)
mydata %>%
    summary_factorlist(dependent = dependent, 
                       explanatory = explanatory,
                       column = TRUE,
                       total_col = TRUE,
                       p = TRUE,
                       add_dependent_label = TRUE,
                       na_include=FALSE
                       # catTest = catTestfisher
                       ) -> table
knitr::kable(table,
             row.names = FALSE,
             align = c('l', 'l', 'r', 'r', 'r'))

20 R Markdown örneği Sağkalım

20.1 Sağkalım için veriyi düzenleme

{r define survival time}
mydata$int <- lubridate::interval(
  lubridate::ymd(mydata$CerrahiTarih),
  lubridate::ymd(mydata$SonTarih)
  )
mydata$OverallTime <- lubridate::time_length(mydata$int, "month")
mydata$OverallTime <- round(mydata$OverallTime, digits = 1)
{r}
## Recoding mydata$Outcome into mydata$Outcome2
mydata$Outcome2 <- recode(mydata$Outcome,
               "Alive" = "0",
               "Dead" = "1")
mydata$Outcome2 <- as.numeric(mydata$Outcome2)

20.2 Kaplan-Meier

{r Kaplan-Meier}
mydata %>%
  finalfit::surv_plot(dependent,
                      explanatory,
                      xlab='Time (months)',
                      pval=TRUE,
                      legend = 'none',
                      break.time.by = 12,
                      xlim = c(0,60),
                      legend.labs = c('a','b')
)

20.3 Sağkalım Tabloları

{r}
km_fit <- survfit(dependent ~ explanatory,
                  data = mydata)
km_fit
{r, eval=FALSE, include=FALSE}
library(survival)
km <- with(mydata, Surv(OverallTime, Outcome2))
# head(km,80)
# plot(km)
{r 1-3-5-yr}
summary(km_fit, times = c(12,36,60))

20.4 Pairwise comparison

{r}
survminer::pairwise_survdiff(formula = Surv(time, Outcome) ~ Group, 
                             data = mydata,
                             p.adjust.method = "BH")

20.5 Multivariate Analysis Survival

{r Multivariate Analysis, eval=FALSE, include=FALSE}
library(finalfit)
library(survival)
explanatoryMultivariate <- explanatoryKM
dependentMultivariate <- dependentKM
mydata %>%
  finalfit(dependentMultivariate, explanatoryMultivariate) -> tMultivariate
knitr::kable(tMultivariate, row.names=FALSE, align=c("l", "l", "r", "r", "r", "r"))

21 jamovi

21.1 jamovi ve R entegrasyonu

Rj Editor – Analyse your data with R in jamovi


21.2 {jmv} paket kodları

jamovi syntax mode


22 Güncellemeler olunca kodlar çalışacak mı?


22.1 Paket Kütüphaneleri

  • packrat / renv

https://environments.rstudio.com


22.2 Docker

  • docker

22.2.1 The Rocker Project

Docker Containers for the R Environment

docker run --rm -ti rocker/r-base

Or get started with an RStudio® instance:

docker run -e PASSWORD=yourpassword --rm -p 8787:8787 rocker/rstudio

and point your browser to localhost:8787 Log in with user/password rstudio/yourpassword


Managing containers


22.3 Yeni R sürümleri

  • RSwitch

https://rud.is/rswitch/

  • Using RSwitch

https://rud.is/rswitch/guide/

: scale 30%


23 Yedeklemeyi nasıl yapacağız

23.1 Projeyi düzgün organize edin

  • pdf
  • R
  • images
  • bib
{r load library}
source(file = here::here("R", "loadLibrary.R"))

23.2 Save Final Data

{r}
saved data after analysis to `mydata.xlsx`.

save.image(file = here::here("data", "mydata_work_space.RData"))

readr::write_rds(x = mydata, path = here::here("data", "mydata_afteranalysis.rds"))

saveRDS(object = mydata, file = here::here("data", "mydata.rds"))

writexl::write_xlsx(mydata, here::here("data", "mydata.xlsx"))

paste0(rownames(file.info(here::here("data", "mydata.xlsx"))), " : ", file.info(here::here("data", "mydata.xlsx"))$ctime)

23.3 GitHub

{r github push}
CommitMessage <- paste("updated on ", Sys.time(), sep = "")
wd <- getwd()
gitCommand <- paste("cd ", 
                    wd,
                    " \n git add . \n git commit --message '",
                    CommitMessage,
                    "' \n git push origin master \n",
                    sep = ""
                    )
system(command = gitCommand,
       intern = TRUE
)

23.4 GitHub Yedekleme

CommitMessage <- paste("updated on ", Sys.time(), sep = "")
wd <- getwd()
gitCommand <- paste("cd ", 
                    wd,
                    " \n git add . \n git commit --message '",
                    CommitMessage,
                    "' \n git push origin master \n",
                    sep = ""
                    )
system(command = gitCommand,
       intern = TRUE
)

24 Her dökümanın sonuna kullandığınız kütüphaneler için atıf yazdırabilirsiniz

{r}
citation()

24.1 Libraries Used

citation()

24.2 Bu oturuma spesifik kullanılan paketler

report::cite_packages(session = sessionInfo())

24.3 Tek tek paket atıfları

{r library citations}
citation("tidyverse")
citation("readxl")
citation("janitor")
citation("report")
citation("finalfit")
citation("ggstatplot")

24.4 Jamovi ve R için atıf örneği


25 Her dökümanın sonuna oturum detaylarınızı yazdırabilirsiniz

{r session info, echo=TRUE}
sessionInfo()

25.1 Session Info

sessionInfo()

26 Sonraki Konular

  • RStudio ile GitHub kullanımı

29 Geri Bildirim




  1. Bu bir derlemedir, mümkün mertebe alıntılara linklerle referans vermeye çalıştım.↩︎

LS0tCnRpdGxlOiBSLCBSU3R1ZGlvIHZlIFJNYXJrZG93biBpbGUgVGVrcmFybGFuYWJpbGlyIFJhcG9yXltCdSBiaXIgZGVybGVtZWRpciwgbcO8bWvDvG4gbWVydGViZSBhbMSxbnTEsWxhcmEgbGlua2xlcmxlIHJlZmVyYW5zIHZlcm1leWUgw6dhbMSxxZ90xLFtLl0KYXV0aG9yOiAiW1NlcmRhciBCYWxjxLEsIE1ELCBQYXRob2xvZ2lzdF0oaHR0cHM6Ly9zYmFsY2kuZ2l0aHViLmlvLykiCmluc3RpdHV0ZTogIltzZXJkYXJiYWxjaS5jb21dKGh0dHBzOi8vd3d3LnNlcmRhcmJhbGNpLmNvbSkiCmRhdGU6ICJgciBmb3JtYXQoU3lzLkRhdGUoKSlgIgpvdXRwdXQ6CiAgcmV2ZWFsanM6OnJldmVhbGpzX3ByZXNlbnRhdGlvbjoKICAgIGluY3JlbWVudGFsOiB0cnVlCiAgICB0aGVtZTogc2t5CiAgICBoaWdobGlnaHQ6IHB5Z21lbnRzCiAgICBjZW50ZXI6IGZhbHNlCiAgICBzbWFydDogdHJ1ZQogICAgdHJhbnNpdGlvbjogZmFkZQogICAgc2VsZl9jb250YWluZWQ6IHRydWUKICAgIGlnX3dpZHRoOiA3CiAgICBmaWdfaGVpZ2h0OiA2CiAgICBmaWdfY2FwdGlvbjogdHJ1ZQogICAgcmV2ZWFsX29wdGlvbnM6CiAgICAgIHNsaWRlTnVtYmVyOiB0cnVlCiAgICAgIHByZXZpZXdMaW5rczogdHJ1ZQogIHJtZHNob3dlcjo6c2hvd2VyX3ByZXNlbnRhdGlvbjoKICB4YXJpbmdhbjo6bW9vbl9yZWFkZXI6CiAgICBsaWJfZGlyOiBsaWJzCiAgICBuYXR1cmU6CiAgICAgIGJlZm9yZUluaXQ6IFsibWFjcm9zLmpzIiwgImh0dHBzOi8vcGxhdGZvcm0udHdpdHRlci5jb20vd2lkZ2V0cy5qcyJdCiAgICAgIGhpZ2hsaWdodFN0eWxlOiBnaXRodWIKICAgICAgaGlnaGxpZ2h0TGluZXM6IHRydWUKICAgICAgY291bnRJbmNyZW1lbnRhbFNsaWRlczogZmFsc2UKICAgIHNlbGZfY29udGFpbmVkOiB0cnVlCiAgaHRtbF9ub3RlYm9vazoKICAgIGZpZ19jYXB0aW9uOiB5ZXMKICAgIGhpZ2hsaWdodDoga2F0ZQogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMKICAgIHRoZW1lOiBmbGF0bHkKICAgIHRvYzogeWVzCiAgICB0b2NfZGVwdGg6IDUKICAgIHRvY19mbG9hdDogeWVzCiAgcHJldHR5ZG9jOjpodG1sX3ByZXR0eToKICAgIHRoZW1lOiBsZW9uaWRzCiAgICBoaWdobGlnaHQ6IGdpdGh1YgogIHBkZl9kb2N1bWVudDoKICAgIHRvYzogeWVzCiAgICB0b2NfZGVwdGg6ICc1JwogIGh0bWxfZG9jdW1lbnQ6CiAgICBmaWdfY2FwdGlvbjogeWVzCiAgICBrZWVwX21kOiB5ZXMKICAgIHRvYzogeWVzCiAgICB0b2NfZGVwdGg6IDUKICAgIHRvY19mbG9hdDogeWVzCmVkaXRvcl9vcHRpb25zOiAKICBjaHVua19vdXRwdXRfdHlwZTogaW5saW5lCi0tLQoKCjwhLS0gT3BlbiBhbGwgbGlua3MgaW4gbmV3IHRhYi0tPiAgCjxiYXNlIHRhcmdldD0iX2JsYW5rIi8+ICAKCgo8IS0tIEdvIHRvIHd3dy5hZGR0aGlzLmNvbS9kYXNoYm9hcmQgdG8gY3VzdG9taXplIHlvdXIgdG9vbHMgLS0+IDxzY3JpcHQgdHlwZT0idGV4dC9qYXZhc2NyaXB0IiBzcmM9Ii8vczcuYWRkdGhpcy5jb20vanMvMzAwL2FkZHRoaXNfd2lkZ2V0LmpzI3B1YmlkPXJhLTViYzM2OTAwYTQwNTA5MGIiPiAgCjwvc2NyaXB0PgoKCgpgYGB7ciBnbG9iYWxfb3B0aW9ucywgaW5jbHVkZT1GQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGZpZy53aWR0aCA9IDEyLCBmaWcuaGVpZ2h0ID0gOCwgZmlnLnBhdGggPSAnRmlncy8nLCBlY2hvID0gRkFMU0UsIHdhcm5pbmcgPSBGQUxTRSwgbWVzc2FnZSA9IEZBTFNFLCBlcnJvciA9IEZBTFNFLCBldmFsID0gVFJVRSwgdGlkeSA9IFRSVUUsIGNvbW1lbnQgPSBOQSwgY2FjaGUgPSBUUlVFKQpgYGAKCgoKYGBge3IgZXZhbD1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgaW5jbHVkZT1GQUxTRX0KIyB4YXJpbmdhbjo6aW5mX21yKCkKIyBzZXJ2cjo6ZGFlbW9uX3N0b3AoMSkKYGBgCgoKCiMgVGVrcmFybGFuYWJpbGlyIEFuYWxpeiB2ZSBSYXBvcgoKClshW10oaHR0cHM6Ly90aGUtdHVyaW5nLXdheS5uZXRsaWZ5LmNvbS9maWd1cmVzL3JlcHJvZHVjaWJpbGl0eS9SZXByb2R1Y2libGVNYXRyaXguanBnKV0oaHR0cHM6Ly90aGUtdHVyaW5nLXdheS5uZXRsaWZ5LmNvbS9yZXByb2R1Y2liaWxpdHkvMDMvZGVmaW5pdGlvbnMuaHRtbCkKCgoKCi0tLQoKCiMjIFJlcGxpY2F0aW9uIENyaXNpcwoKIVtdKGZpZ3VyZXMvcmVwbGljYXRpb25DcmlzaXMucG5nKQoKaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvUmVwbGljYXRpb25fY3Jpc2lzCgoKLS0tCgojIyBSZXBsaWNhdGlvbiBDcmlzaXMgRXhjZWwgVmVyc2lvbgoKWyFbXShmaWd1cmVzL2dlbmVOYW1lc0V4Y2VsLnBuZyldKGh0dHBzOi8vZ2Vub21lYmlvbG9neS5iaW9tZWRjZW50cmFsLmNvbS9hcnRpY2xlcy8xMC4xMTg2L3MxMzA1OS0wMTYtMTA0NC03KQoKCi0tLQoKIyBSU3R1ZGlvIGlsZSBwcm9qZSBvbHXFn3R1cgoKCgohW10oaW1hZ2VzL1JTdHVkaW8tTmV3UHJvamVjdC5naWYpCgoKCi0tLQoKIyBSIE5vdGVib29rICAKCiMjIFIgTm90ZWJvb2sgZMO2a8O8bWFuxLEgb2x1xZ90dXJtYSAKCgohW10oaW1hZ2VzL1JOb3RlYm9vazEuZ2lmKQoKLS0tCgojIyBSIE5vdGVib29rJ3RhbiBodG1sLCBwZGYgdmUgd29yZCBvbHXFn3R1cm1hICAKCgohW10oaW1hZ2VzL1JOb3RlYm9vazIuZ2lmKQoKCi0tLQoKIyMgUk5vdGVib29rIHZzIFJNYXJrZG93biAgCgo8aWZyYW1lIHdpZHRoPSI1NjAiIGhlaWdodD0iMzE1IiBzcmM9Imh0dHBzOi8vd3d3LnlvdXR1YmUuY29tL2VtYmVkL3pOeloxUGZVRE5rIiBmcmFtZWJvcmRlcj0iMCIgYWxsb3c9ImFjY2VsZXJvbWV0ZXI7IGF1dG9wbGF5OyBlbmNyeXB0ZWQtbWVkaWE7IGd5cm9zY29wZTsgcGljdHVyZS1pbi1waWN0dXJlIiBhbGxvd2Z1bGxzY3JlZW4+PC9pZnJhbWU+ICAKCmh0dHBzOi8veW91dHUuYmUvek56WjFQZlVETmsKCgotLS0KCiMgUiBNYXJrZG93bgoKIyMgSGVtIGtlbmRpIGtvZGxhcsSxIGhlbSBkZSBodG1sIGtvZGxhcsSxIHlhesSxbGFiaWxpcgoKaHR0cHM6Ly9ybWFya2Rvd24ucnN0dWRpby5jb20KCjxpZnJhbWUgc3JjPSJodHRwczovL3BsYXllci52aW1lby5jb20vdmlkZW8vMTc4NDg1NDE2P2NvbG9yPTQyOGJjYSZ0aXRsZT0wJmJ5bGluZT0wJnBvcnRyYWl0PTAiIHdpZHRoPSI2NDAiIGhlaWdodD0iNDAwIiBmcmFtZWJvcmRlcj0iMCIgYWxsb3c9ImF1dG9wbGF5OyBmdWxsc2NyZWVuIiBhbGxvd2Z1bGxzY3JlZW4+PC9pZnJhbWU+CjxwPjxhIGhyZWY9Imh0dHBzOi8vdmltZW8uY29tLzE3ODQ4NTQxNiI+V2hhdCBpcyBSIE1hcmtkb3duPzwvYT4gZnJvbSA8YSBocmVmPSJodHRwczovL3ZpbWVvLmNvbS9yc3R1ZGlvaW5jIj5SU3R1ZGlvLCBJbmMuPC9hPiBvbiA8YSBocmVmPSJodHRwczovL3ZpbWVvLmNvbSI+VmltZW88L2E+LjwvcD4KCi0tLQoKIyMgUiBNYXJrZG93bjogVGhlIERlZmluaXRpdmUgR3VpZGUKCmh0dHBzOi8vYm9va2Rvd24ub3JnL3lpaHVpL3JtYXJrZG93bi8KCgotLS0KCiMjIFIgTWFya2Rvd24gc3ludGF4CgpodHRwczovL2dpc3QuZ2l0aHViLmNvbS9NaW5oYXNLYW1hbC83ZmRlYmI3YzQyNGQyMzE0OTE0MAoKCjxzY3JpcHQgc3JjPSJodHRwczovL2dpc3QuZ2l0aHViLmNvbS9NaW5oYXNLYW1hbC83ZmRlYmI3YzQyNGQyMzE0OTE0MC5qcyI+PC9zY3JpcHQ+CgoKCi0tLQoKIyMgUmVtZWR5IFBhY2thZ2UgIAoKWzxpbWcgc3JjPSJodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vVGhpbmtSLW9wZW4vcmVtZWR5L21hc3Rlci9yZWZlcmVuY2UvZmlndXJlcy90aGlua3ItaGV4LXJlbWVkeS5wbmciIHdpZHRoPTI1MHB4Pl0oaHR0cHM6Ly9naXRodWIuY29tL1RoaW5rUi1vcGVuL3JlbWVkeSkKCgotLS0KCiMjIyBSZW1lZHkgIAoKWzxpbWcgc3JjPSJodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vVGhpbmtSLW9wZW4vcmVtZWR5L21hc3Rlci9yZWZlcmVuY2UvZmlndXJlcy9yZW1lZHlfZXhhbXBsZS5naWYiIHdpZHRoPTUwMHB4Pl0oaHR0cHM6Ly9naXRodWIuY29tL1RoaW5rUi1vcGVuL3JlbWVkeSkKCgotLS0KCiMjIFIgTWFya2Rvd24gcGFrZXQgdmUgxZ9hYmxvbmxhcsSxICAKCmh0dHBzOi8vYm9va2Rvd24ub3JnL3lpaHVpL3JtYXJrZG93bi9kb2N1bWVudC10ZW1wbGF0ZXMuaHRtbAoKCiFbXShpbWFnZXMvUk1hcmtkb3duVGVtcGxhdGVzLmdpZikKCgotLS0KCiMjIFJlbmRlciBNYXJrZG93biB2aWEgY29kZQoKKmluc2lkZSBSKgoKYGBgCm1hcmtkb3duOjptYXJrZG93blRvSFRNTCgnbWFya2Rvd25fZXhhbXBsZS5tZCcsIAonbWFya2Rvd25fZXhhbXBsZS5odG1sJykKYGBgCgoqY29tbWFuZCBsaW5lKgoKYGBgClIgLWUgIm1hcmtkb3duOjptYXJrZG93blRvSFRNTCgnbWFya2Rvd25fZXhhbXBsZS5tZCcsCidtYXJrZG93bl9leGFtcGxlLmh0bWwnKSIKYGBgCgotLS0KCgojIyBwYW5kb2MgUnN0dWRpbyBpbnRlZ3JhdGlvbgoKKmNvbW1hbmQgbGluZSoKCmBgYApleHBvcnQgUEFUSD0kUEFUSDovQXBwbGljYXRpb25zL1JTdHVkaW8uYXBwL0NvbnRlbnRzL01hY09TL3BhbmRvYwpgYGAKCgpgYGAKUiAtZSAicm1hcmtkb3duOjpyZW5kZXIoJ21hcmtkb3duX2V4YW1wbGUubWQnKSIKYGBgCgoKLS0tCgojIFJNYXJrZG93biBgY2h1bmtgIGnDp2luZGUgYFJgIGtvZGxhcsSxbsSxIMOnYWzEscWfdMSxcm1hCgoKYGBgCntyLCByZXN1bHRzPSdhc2lzJ30KIGlyaXMgJT4lCiAgdGliYmxlOjphc190aWJibGUoKSAlPiUKICBkZXRhaWxzOjpkZXRhaWxzKHN1bW1hcnkgPSAndGliYmxlJykKYGBgCgotLS0KCiMgTWV0aW4gYXJhc8SxbmRhIGBSYCBrb2RsYXLEsW7EsSDDp2FsxLHFn3TEsXJtYQoKCiFbXShpbWFnZXMvaW5saW5lUkNvZGUucG5nKQoKCi0tLQoKIyBDaHVuayBPcHRpb25zCgojIyBHbG9iYWwgT3B0aW9ucwoKYGBgCntyIGdsb2JhbF9vcHRpb25zIDEsIGluY2x1ZGU9RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldChmaWcud2lkdGggPSAxMiwKICAgICAgICAgICAgICAgICAgICAgIGZpZy5oZWlnaHQgPSA4LAogICAgICAgICAgICAgICAgICAgICAgZmlnLnBhdGggPSAnRmlncy8nLAogICAgICAgICAgICAgICAgICAgICAgZWNobyA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgd2FybmluZyA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgbWVzc2FnZSA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgZXJyb3IgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgIGV2YWwgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgdGlkeSA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICBjb21tZW50ID0gTkEpCmBgYAoKLS0tCgojIyBPdGhlciBDb2RlIExhbmd1YWdlcwoKClshW10oaHR0cHM6Ly9kMzN3dWJyZmtpMGw2OC5jbG91ZGZyb250Lm5ldC8xNjIzNDdlZjVhZmUyMTlkYTIyZmI3ZDdkOWE1OTg5ZjJjM2U1YTg1LzU5MzE2L2xlc3Nvbi1pbWFnZXMvbGFuZ3VhZ2VzLTEtZGVtb3MucG5nKV0oaHR0cHM6Ly9ybWFya2Rvd24ucnN0dWRpby5jb20vbGVzc29uLTUuaHRtbCkKCgotLS0KCgojIFIgTWFya2Rvd24ga29kIMO2cm5lxJ9pICAKCgpgYGAKe3J9CmRhdGEoImNhbmNlciIpCmNhbmNlcgpmb3JlaWduOjp3cml0ZS5mb3JlaWduKGRmID0gY2FuY2VyLAogICAgICAgICAgICAgICAgICAgICAgICBkYXRhZmlsZSA9ICJkYXRhL2NhbmNlci5zYXYiLAogICAgICAgICAgICAgICAgICAgICAgICBjb2RlZmlsZSA9ICJkYXRhL2NhbmNlci5zcG8iLAogICAgICAgICAgICAgICAgICAgICAgICBwYWNrYWdlID0gIlNQU1MiCiAgICAgICAgICAgICAgICAgICAgICAgICkKYGBgCgoKLS0tCgojIFIgTWFya2Rvd24gUGFrZXQgw4dhxJ/EsXJtYSDwn5OmICAgIAoKCmBgYAp7cn0Kc3VwcHJlc3NQYWNrYWdlU3RhcnR1cE1lc3NhZ2VzKGxpYnJhcnkoInRpZHl2ZXJzZSIpKQpzdXBwcmVzc1BhY2thZ2VTdGFydHVwTWVzc2FnZXMobGlicmFyeSgic3Vydml2YWwiKSkKYGBgCgotLS0KCiMjIFPEsWsga3VsbGFuZMSxxJ/EsW0gcGFrZXRsZXIg8J+TpiAgCgp7dGlkeXZlcnNlfQp7dGlkeWxvZ30KCntsdWJyaWRhdGV9CntqYW5pdG9yfQoKe3JlYWR4bH0Ke2ZvcmVpZ259Cgp7c3VtbWFyeXRvb2xzfQp7Z2dzdGF0c3Bsb3R9Cnt0YW5ncmFtfQp7ZmluYWxmaXR9Cntwc3ljaG99CntqbXZ9Cgp7c3Vydml2YWx9CntzdXJ2bWluZXJ9Cgp7cmVwb3J0fQp7a2FibGVFeHRyYX0KCi0tLQoKIyBSIE1hcmtkb3duIFZlcmkgWcO8a2xlbWUgU1BTUyAgCgohW10oaW1hZ2VzL2ltcG9ydFNQU1MuZ2lmKQoKCi0tLQoKIyBSIE1hcmtkb3duIFZlcmkgWcO8a2xlbWUgRXhjZWwgIAoKCgohW10oaW1hZ2VzL2ltcG9ydEV4Y2VsLmdpZikKCgotLS0KCiMgVmVyaSBHw7Zyw7xudMO8bGVtZQoKCmBgYAp7cn0KVmlldyhteWRhdGEpCmdsaW1wc2UobXlkYXRhKQpgYGAKCgoKCi0tLQoKIyBWZXJpIETDvHplbmxlbWUKCmBgYAp7cn0KbXlkYXRhIDwtIGphbml0b3I6OmNsZWFuX25hbWVzKG15ZGF0YSkKYGBgCgpgYGAKe3J9Cm15ZGF0YSRzb250YXJpaCA8LSBqYW5pdG9yOjpleGNlbF9udW1lcmljX3RvX2RhdGUoCiAgYXMubnVtZXJpYyhteWRhdGEkb2x1bV90YXJpaGkpCiAgKQpgYGAKCgotLS0KCiMgUmVjb2RlCgoKYGBgCntyfQpteWRhdGEkT3V0Y29tZSA8LSAiRGVhZCIKbXlkYXRhJE91dGNvbWVbbXlkYXRhJG9sdW1fdGFyaWhpID09ICJ5b2siXSA8LSAiQWxpdmUiCmBgYAoKCmBgYAp7cn0KIyMgUmVjb2RpbmcgbXlkYXRhJGNpbnNpeWV0IGludG8gbXlkYXRhJENpbnNpeWV0Cm15ZGF0YSRDaW5zaXlldCA8LSByZWNvZGUobXlkYXRhJGNpbnNpeWV0LAogICAgICAgICAgICAgICAiSyIgPSAiS2FkaW4iLAogICAgICAgICAgICAgICAiRSIgPSAiRXJrZWsiKQpteWRhdGEkQ2luc2l5ZXQgPC0gZmFjdG9yKG15ZGF0YSRDaW5zaXlldCkKYGBgCgoKLS0tCgojIFJlY29kZSByZWd1bGFyIGV4cHJlc3Npb24KCgpgYGAKe3IgcmVjb2RlIFROTSBzdGFnZX0KI3BUMk4wTXggLT4gMgpteWRhdGEkVHN0YWdlIDwtIHN0cmluZ3I6OnN0cl9tYXRjaCgKICBteWRhdGEkcGF0b2xvamlrX2V2cmUsIAogIHBhc3RlKCcoLispJywgIk4iLCBzZXA9JycpKVssMl0KKQpgYGAKCgotLS0KCiMgUmVjb2RlIHJlZ3VsYXIgZXhwcmVzc2lvbiBjYXNlX3doZW4KCmBgYAp7ciByZWNvZGUgVE5NMn0KbXlkYXRhIDwtIG15ZGF0YSAlPiUgCiAgICBtdXRhdGUoCiAgICAgICAgVF9zdGFnZSA9IGNhc2Vfd2hlbigKICAgICAgICAgICAgZ3JlcGwocGF0dGVybiA9ICJUMSIsIHggPSAuJFRzdGFnZSkgPT0gVFJVRSB+ICJUMSIsCiAgICAgICAgICAgIGdyZXBsKHBhdHRlcm4gPSAiVDIiLCB4ID0gLiRUc3RhZ2UpID09IFRSVUUgfiAiVDIiLAogICAgICAgICAgICBncmVwbChwYXR0ZXJuID0gIlQzIiwgeCA9IC4kVHN0YWdlKSA9PSBUUlVFIH4gIlQzIiwKICAgICAgICAgICAgZ3JlcGwocGF0dGVybiA9ICJUNCIsIHggPSAuJFRzdGFnZSkgPT0gVFJVRSB+ICJUNCIsCiAgICAgICAgICAgIFRSVUUgfiAiVHgiCiAgICAgICAgKQogICAgKQpgYGAKCi0tLQoKIyBSZWNvZGUgcmVndWxhciBleHByZXNzaW9uIGNhc2Vfd2hlbgoKYGBgCntyfQpteWRhdGEgPC0gbXlkYXRhICU+JSAKICAgIG11dGF0ZSgKVHVtb3JQREwxZ3IxID0gY2FzZV93aGVuKAogICAgICAgIHRfcGRsMSA8IDEgfiAia3VjdWsxIiwKICAgICAgICB0X3BkbDEgPj0gMSB+ICJidXl1a2VzaXQxIgogICAgKQogICAgKQpgYGAKCi0tLQoKIyBSIE1hcmtkb3duIFRhbsSxbWxhecSxY8SxIMSwc3RhdGlzdGlrbGVyICAKCgpgYGAKe3J9CmxpYnJhcnkoc3VtbWFyeXRvb2xzKQp2aWV3KGRmU3VtbWFyeShjb2xvbl9zKSkKYGBgCgoKLS0tCgoKQSBiZWdpbm5lciBraXQgZm9yICNyc3RhdHMKVGhlIExhbmRzY2FwZSBvZiBSIFBhY2thZ2VzIGZvciBBdXRvbWF0ZWQgRXhwbG9yYXRvcnkgRGF0YSBBbmFseXNpcwpodHRwczovL2pvdXJuYWwuci1wcm9qZWN0Lm9yZy9hcmNoaXZlLzIwMTkvUkotMjAxOS0wMzMvCgoKCkBhcnRpY2xle1JKLTIwMTktMDMzLAogIGF1dGhvciA9IHtNYXRldXN6IFN0YW5pYWsgYW5kIFByemVteXPFgmF3IEJpZWNla30sCiAgdGl0bGUgPSB7e1RoZSBMYW5kc2NhcGUgb2YgUiBQYWNrYWdlcyBmb3IgQXV0b21hdGVkIEV4cGxvcmF0b3J5IERhdGEKICAgICAgICAgIEFuYWx5c2lzfX0sCiAgeWVhciA9IHsyMDE5fSwKICBqb3VybmFsID0ge3tUaGUgUiBKb3VybmFsfX0sCiAgZG9pID0gezEwLjMyNjE0L1JKLTIwMTktMDMzfSwKICB1cmwgPSB7aHR0cHM6Ly9qb3VybmFsLnItcHJvamVjdC5vcmcvYXJjaGl2ZS8yMDE5L1JKLTIwMTktMDMzL2luZGV4Lmh0bWx9Cn0KCgoKLS0tCgoKIyMgVGFibGUgT25lICAKCgpgYGAKe3IsIHJlc3VsdHM9J2FzaXMnfQojIGNhdChuYW1lcyhteWRhdGEpLCBzZXAgPSAiICsgXG4iKQpsaWJyYXJ5KGFyc2VuYWwpCnRhYjEgPC0gdGFibGVieSh+IENpbnNpeWV0ICsgCllhcyArIApUdW1vclllcmxlc2ltaQogICAgICAgICAgICAgICAgLAogICAgICAgICAgICAgICAgZGF0YSA9IG15ZGF0YSkKc3VtbWFyeSh0YWIxKQpgYGAKCi0tLQoKIyMgVGhlIEdyYW1tYXIgb2YgVGFibGVzCgoKW3RhbmdyYW06IFRoZSBHcmFtbWFyIG9mIFRhYmxlc10oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL3RhbmdyYW0vKQoKW0EgZ3JhbW1hciBvZiB0YWJsZXNdKGh0dHBzOi8vZ2l0aHViLmNvbS9sZWVwZXIvdHR0YWJsZSkKCltHcmFtbWFyIG9mIFRhYmxlcz9dKGh0dHBzOi8vZ2lzdC5naXRodWIuY29tL2xlZXBlci9mOWNmYmU2YmQxODU3NjM3NjJlMTI2YTRkOGQ3YzI4NikKCltFYXNpbHkgZ2VuZXJhdGUgaW5mb3JtYXRpb24tcmljaCwgcHVibGljYXRpb24tcXVhbGl0eSB0YWJsZXMgZnJvbSBSXShodHRwczovL2d0LnJzdHVkaW8uY29tKQoKCi0tLQoKIyMgS2F0ZWdvcmlrIFZlcmlsZXIKCmBgYAp7cn0KbXlkYXRhICU+JSAKICBqYW5pdG9yOjp0YWJ5bChDYXRlZ29yaWNhbCkgJT4lCiAgYWRvcm5fcGN0X2Zvcm1hdHRpbmcocm91bmRpbmcgPSAnaGFsZiB1cCcsCiAgICAgICAgICAgICAgICAgICAgICAgZGlnaXRzID0gMSkgJT4lCiAga25pdHI6OmthYmxlKCkKYGBgCgpgYGAKe3IgY3Jvc3N0YWJsZX0KbXlkYXRhICU+JQogICAgc3VtbWFyeV9mYWN0b3JsaXN0KGRlcGVuZGVudCA9IGRlcGVuZGVudCwgCiAgICAgICAgICAgICAgICAgICAgICAgZXhwbGFuYXRvcnkgPSBleHBsYW5hdG9yeSwKICAgICAgICAgICAgICAgICAgICAgICB0b3RhbF9jb2wgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgIHAgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgIGFkZF9kZXBlbmRlbnRfbGFiZWwgPSBUUlVFKSAtPiB0YWJsZQprbml0cjo6a2FibGUodGFibGUsIHJvdy5uYW1lcyA9IEZBTFNFLCBhbGlnbiA9IGMoJ2wnLCAnbCcsICdyJywgJ3InLCAncicpKQpgYGAKCi0tLQoKIyMgS2F0ZWdvcmlrIFZlcmlsZXIgacOnaW4gR3JhZmlrbGVyICAKCmBgYAp7ciBnZ3N0YXRwbG90LCBsYXlvdXQ9J2wtcGFnZSd9Cm15ZGF0YSAlPiUgCiAgICBnZ3N0YXRzcGxvdDo6Z2diYXJzdGF0cyhkYXRhID0gLiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1haW4gPSBDYXRlZ29yaWNhbF92YXJpYWJsZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbmRpdGlvbiA9ICBkZXBlbmRlbnRfdmFyaWFibGUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICkKYGBgCgotLS0KCgojIyBDb250aW5pb3VzIFZhcmlhYmxlcwoKYGBgCntyfQpteWRhdGEgJT4lIApqbXY6OmRlc2NyaXB0aXZlcygKICAgIGRhdGEgPSAuLAogICAgdmFycyA9IGMoeWFzKSwKICAgIGhpc3QgPSBUUlVFLAogICAgZGVucyA9IFRSVUUsCiAgICBib3ggPSBUUlVFLAogICAgdmlvbGluID0gVFJVRSwKICAgIGRvdCA9IFRSVUUsCiAgICBtb2RlID0gVFJVRSwKICAgIHNkID0gVFJVRSwKICAgIHZhcmlhbmNlID0gVFJVRSwKICAgIHNrZXcgPSBUUlVFLAogICAga3VydCA9IFRSVUUsCiAgICBxdWFydCA9IFRSVUUpCmBgYAoKLS0tCgojIFIgTWFya2Rvd24gw7ZybmXEn2kgw4dhcHJheiBUYWJsb2xhciAgCgpgYGAKe3IgY3Jvc3N0YWJsZX0KbGlicmFyeShmaW5hbGZpdCkKbXlkYXRhICU+JQogICAgc3VtbWFyeV9mYWN0b3JsaXN0KGRlcGVuZGVudCA9IGRlcGVuZGVudCwgCiAgICAgICAgICAgICAgICAgICAgICAgZXhwbGFuYXRvcnkgPSBleHBsYW5hdG9yeSwKICAgICAgICAgICAgICAgICAgICAgICBjb2x1bW4gPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgIHRvdGFsX2NvbCA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgcCA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgYWRkX2RlcGVuZGVudF9sYWJlbCA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgbmFfaW5jbHVkZT1GQUxTRQogICAgICAgICAgICAgICAgICAgICAgICMgY2F0VGVzdCA9IGNhdFRlc3RmaXNoZXIKICAgICAgICAgICAgICAgICAgICAgICApIC0+IHRhYmxlCmtuaXRyOjprYWJsZSh0YWJsZSwKICAgICAgICAgICAgIHJvdy5uYW1lcyA9IEZBTFNFLAogICAgICAgICAgICAgYWxpZ24gPSBjKCdsJywgJ2wnLCAncicsICdyJywgJ3InKSkKYGBgCgotLS0KCiMgUiBNYXJrZG93biDDtnJuZcSfaSBTYcSfa2FsxLFtICAKCi0gRHJhd2luZyBTdXJ2aXZhbCBDdXJ2ZXMgVXNpbmcgZ2dwbG90MiAgCmh0dHBzOi8vcnBrZ3MuZGF0YW5vdmlhLmNvbS9zdXJ2bWluZXIvcmVmZXJlbmNlL2dnc3VydnBsb3QuaHRtbAoKIyMgU2HEn2thbMSxbSBpw6dpbiB2ZXJpeWkgZMO8emVubGVtZQoKYGBgCntyIGRlZmluZSBzdXJ2aXZhbCB0aW1lfQpteWRhdGEkaW50IDwtIGx1YnJpZGF0ZTo6aW50ZXJ2YWwoCiAgbHVicmlkYXRlOjp5bWQobXlkYXRhJENlcnJhaGlUYXJpaCksCiAgbHVicmlkYXRlOjp5bWQobXlkYXRhJFNvblRhcmloKQogICkKbXlkYXRhJE92ZXJhbGxUaW1lIDwtIGx1YnJpZGF0ZTo6dGltZV9sZW5ndGgobXlkYXRhJGludCwgIm1vbnRoIikKbXlkYXRhJE92ZXJhbGxUaW1lIDwtIHJvdW5kKG15ZGF0YSRPdmVyYWxsVGltZSwgZGlnaXRzID0gMSkKYGBgCgpgYGAKe3J9CiMjIFJlY29kaW5nIG15ZGF0YSRPdXRjb21lIGludG8gbXlkYXRhJE91dGNvbWUyCm15ZGF0YSRPdXRjb21lMiA8LSByZWNvZGUobXlkYXRhJE91dGNvbWUsCiAgICAgICAgICAgICAgICJBbGl2ZSIgPSAiMCIsCiAgICAgICAgICAgICAgICJEZWFkIiA9ICIxIikKbXlkYXRhJE91dGNvbWUyIDwtIGFzLm51bWVyaWMobXlkYXRhJE91dGNvbWUyKQpgYGAKCi0tLQoKIyMgS2FwbGFuLU1laWVyCgpgYGAKe3IgS2FwbGFuLU1laWVyfQpteWRhdGEgJT4lCiAgZmluYWxmaXQ6OnN1cnZfcGxvdChkZXBlbmRlbnQsCiAgICAgICAgICAgICAgICAgICAgICBleHBsYW5hdG9yeSwKICAgICAgICAgICAgICAgICAgICAgIHhsYWI9J1RpbWUgKG1vbnRocyknLAogICAgICAgICAgICAgICAgICAgICAgcHZhbD1UUlVFLAogICAgICAgICAgICAgICAgICAgICAgbGVnZW5kID0gJ25vbmUnLAogICAgICAgICAgICAgICAgICAgICAgYnJlYWsudGltZS5ieSA9IDEyLAogICAgICAgICAgICAgICAgICAgICAgeGxpbSA9IGMoMCw2MCksCiAgICAgICAgICAgICAgICAgICAgICBsZWdlbmQubGFicyA9IGMoJ2EnLCdiJykKKQpgYGAKCi0tLQoKIyMgU2HEn2thbMSxbSBUYWJsb2xhcsSxCgpgYGAKe3J9CmttX2ZpdCA8LSBzdXJ2Zml0KGRlcGVuZGVudCB+IGV4cGxhbmF0b3J5LAogICAgICAgICAgICAgICAgICBkYXRhID0gbXlkYXRhKQprbV9maXQKYGBgCgpgYGAKe3IsIGV2YWw9RkFMU0UsIGluY2x1ZGU9RkFMU0V9CmxpYnJhcnkoc3Vydml2YWwpCmttIDwtIHdpdGgobXlkYXRhLCBTdXJ2KE92ZXJhbGxUaW1lLCBPdXRjb21lMikpCiMgaGVhZChrbSw4MCkKIyBwbG90KGttKQpgYGAKCmBgYAp7ciAxLTMtNS15cn0Kc3VtbWFyeShrbV9maXQsIHRpbWVzID0gYygxMiwzNiw2MCkpCmBgYAoKLS0tCgojIyBQYWlyd2lzZSBjb21wYXJpc29uCgpgYGAKe3J9CnN1cnZtaW5lcjo6cGFpcndpc2Vfc3VydmRpZmYoZm9ybXVsYSA9IFN1cnYodGltZSwgT3V0Y29tZSkgfiBHcm91cCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0YSA9IG15ZGF0YSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwLmFkanVzdC5tZXRob2QgPSAiQkgiKQpgYGAKCi0tLQoKIyMgTXVsdGl2YXJpYXRlIEFuYWx5c2lzIFN1cnZpdmFsCgpgYGAKe3IgTXVsdGl2YXJpYXRlIEFuYWx5c2lzLCBldmFsPUZBTFNFLCBpbmNsdWRlPUZBTFNFfQpsaWJyYXJ5KGZpbmFsZml0KQpsaWJyYXJ5KHN1cnZpdmFsKQpleHBsYW5hdG9yeU11bHRpdmFyaWF0ZSA8LSBleHBsYW5hdG9yeUtNCmRlcGVuZGVudE11bHRpdmFyaWF0ZSA8LSBkZXBlbmRlbnRLTQpteWRhdGEgJT4lCiAgZmluYWxmaXQoZGVwZW5kZW50TXVsdGl2YXJpYXRlLCBleHBsYW5hdG9yeU11bHRpdmFyaWF0ZSkgLT4gdE11bHRpdmFyaWF0ZQprbml0cjo6a2FibGUodE11bHRpdmFyaWF0ZSwgcm93Lm5hbWVzPUZBTFNFLCBhbGlnbj1jKCJsIiwgImwiLCAiciIsICJyIiwgInIiLCAiciIpKQpgYGAKCi0tLQoKIyBqYW1vdmkKCiMjIGphbW92aSB2ZSBSIGVudGVncmFzeW9udQoKW1JqIEVkaXRvciDigJMgQW5hbHlzZSB5b3VyIGRhdGEgd2l0aCBSIGluIGphbW92aV0oaHR0cHM6Ly9ibG9nLmphbW92aS5vcmcvMjAxOC8wNy8zMC9yai5odG1sKQoKIVtdKGltYWdlcy9qYW1vdmlSakVkaXRvci5naWYpCgotLS0KCiMjIHtqbXZ9IHBha2V0IGtvZGxhcsSxCgpbamFtb3ZpIHN5bnRheCBtb2RlXShodHRwczovL3d3dy5qYW1vdmkub3JnL3VzZXItbWFudWFsLmh0bWwjc3ludGF4LW1vZGUpCgoKIVtdKGltYWdlcy9qYW1vdmlTeW50YXhNb2RlLmdpZikKCgoKLS0tCgojIEfDvG5jZWxsZW1lbGVyIG9sdW5jYSBrb2RsYXIgw6dhbMSxxZ9hY2FrIG3EsT8KCgotLS0KCiMjIFBha2V0IEvDvHTDvHBoYW5lbGVyaQoKLSBwYWNrcmF0IC8gcmVudgoKaHR0cHM6Ly9lbnZpcm9ubWVudHMucnN0dWRpby5jb20KCi0tLQoKIyMgRG9ja2VyCgotIGRvY2tlcgoKLS0tCgojIyMgVGhlIFJvY2tlciBQcm9qZWN0CgpEb2NrZXIgQ29udGFpbmVycyBmb3IgdGhlIFIgRW52aXJvbm1lbnQKCmBgYApkb2NrZXIgcnVuIC0tcm0gLXRpIHJvY2tlci9yLWJhc2UKYGBgCgpPciBnZXQgc3RhcnRlZCB3aXRoIGFuIFJTdHVkaW/CriBpbnN0YW5jZToKCmBgYApkb2NrZXIgcnVuIC1lIFBBU1NXT1JEPXlvdXJwYXNzd29yZCAtLXJtIC1wIDg3ODc6ODc4NyByb2NrZXIvcnN0dWRpbwpgYGAKCmFuZCBwb2ludCB5b3VyIGJyb3dzZXIgdG8gW2xvY2FsaG9zdDo4Nzg3XShsb2NhbGhvc3Q6ODc4NykKTG9nIGluIHdpdGggdXNlci9wYXNzd29yZCByc3R1ZGlvL3lvdXJwYXNzd29yZCAKCi0tLQoKWyFbXShpbWFnZXMvVGhlUm9ja2VyUHJvamVjdC5wbmcpXShodHRwczovL3d3dy5yb2NrZXItcHJvamVjdC5vcmcpCgpbTWFuYWdpbmcgY29udGFpbmVyc10oaHR0cHM6Ly93d3cucm9ja2VyLXByb2plY3Qub3JnL3VzZS9tYW5hZ2luZ19jb250YWluZXJzLykKCgotLS0KCiMjIFllbmkgUiBzw7xyw7xtbGVyaSAKCi0gUlN3aXRjaAoKaHR0cHM6Ly9ydWQuaXMvcnN3aXRjaC8KCi0gVXNpbmcgUlN3aXRjaAoKaHR0cHM6Ly9ydWQuaXMvcnN3aXRjaC9ndWlkZS8KCgohWzogc2NhbGUgMzAlXShodHRwczovL3J1ZC5pcy9yc3dpdGNoL2d1aWRlL21lbnUtaW5mby5wbmcpCgoKLS0tCgojIFllZGVrbGVtZXlpIG5hc8SxbCB5YXBhY2HEn8SxegoKIyMgUHJvamV5aSBkw7x6Z8O8biBvcmdhbml6ZSBlZGluCgotIHBkZgotIFIKLSBpbWFnZXMKLSBiaWIKCmBgYAp7ciBsb2FkIGxpYnJhcnl9CnNvdXJjZShmaWxlID0gaGVyZTo6aGVyZSgiUiIsICJsb2FkTGlicmFyeS5SIikpCmBgYAoKLS0tCgojIyBTYXZlIEZpbmFsIERhdGEKCmBgYAp7cn0Kc2F2ZWQgZGF0YSBhZnRlciBhbmFseXNpcyB0byBgbXlkYXRhLnhsc3hgLgoKc2F2ZS5pbWFnZShmaWxlID0gaGVyZTo6aGVyZSgiZGF0YSIsICJteWRhdGFfd29ya19zcGFjZS5SRGF0YSIpKQoKcmVhZHI6OndyaXRlX3Jkcyh4ID0gbXlkYXRhLCBwYXRoID0gaGVyZTo6aGVyZSgiZGF0YSIsICJteWRhdGFfYWZ0ZXJhbmFseXNpcy5yZHMiKSkKCnNhdmVSRFMob2JqZWN0ID0gbXlkYXRhLCBmaWxlID0gaGVyZTo6aGVyZSgiZGF0YSIsICJteWRhdGEucmRzIikpCgp3cml0ZXhsOjp3cml0ZV94bHN4KG15ZGF0YSwgaGVyZTo6aGVyZSgiZGF0YSIsICJteWRhdGEueGxzeCIpKQoKcGFzdGUwKHJvd25hbWVzKGZpbGUuaW5mbyhoZXJlOjpoZXJlKCJkYXRhIiwgIm15ZGF0YS54bHN4IikpKSwgIiA6ICIsIGZpbGUuaW5mbyhoZXJlOjpoZXJlKCJkYXRhIiwgIm15ZGF0YS54bHN4IikpJGN0aW1lKQoKYGBgCgotLS0KCiMjIEdpdEh1YiAgCgpgYGAKe3IgZ2l0aHViIHB1c2h9CkNvbW1pdE1lc3NhZ2UgPC0gcGFzdGUoInVwZGF0ZWQgb24gIiwgU3lzLnRpbWUoKSwgc2VwID0gIiIpCndkIDwtIGdldHdkKCkKZ2l0Q29tbWFuZCA8LSBwYXN0ZSgiY2QgIiwgCiAgICAgICAgICAgICAgICAgICAgd2QsCiAgICAgICAgICAgICAgICAgICAgIiBcbiBnaXQgYWRkIC4gXG4gZ2l0IGNvbW1pdCAtLW1lc3NhZ2UgJyIsCiAgICAgICAgICAgICAgICAgICAgQ29tbWl0TWVzc2FnZSwKICAgICAgICAgICAgICAgICAgICAiJyBcbiBnaXQgcHVzaCBvcmlnaW4gbWFzdGVyIFxuIiwKICAgICAgICAgICAgICAgICAgICBzZXAgPSAiIgogICAgICAgICAgICAgICAgICAgICkKc3lzdGVtKGNvbW1hbmQgPSBnaXRDb21tYW5kLAogICAgICAgaW50ZXJuID0gVFJVRQopCmBgYAoKLS0tCgojIyBHaXRIdWIgWWVkZWtsZW1lCgpgYGB7ciBnaXRodWIgcHVzaCwgZWNobz1UUlVFfQpDb21taXRNZXNzYWdlIDwtIHBhc3RlKCJ1cGRhdGVkIG9uICIsIFN5cy50aW1lKCksIHNlcCA9ICIiKQp3ZCA8LSBnZXR3ZCgpCmdpdENvbW1hbmQgPC0gcGFzdGUoImNkICIsIAogICAgICAgICAgICAgICAgICAgIHdkLAogICAgICAgICAgICAgICAgICAgICIgXG4gZ2l0IGFkZCAuIFxuIGdpdCBjb21taXQgLS1tZXNzYWdlICciLAogICAgICAgICAgICAgICAgICAgIENvbW1pdE1lc3NhZ2UsCiAgICAgICAgICAgICAgICAgICAgIicgXG4gZ2l0IHB1c2ggb3JpZ2luIG1hc3RlciBcbiIsCiAgICAgICAgICAgICAgICAgICAgc2VwID0gIiIKICAgICAgICAgICAgICAgICAgICApCnN5c3RlbShjb21tYW5kID0gZ2l0Q29tbWFuZCwKICAgICAgIGludGVybiA9IFRSVUUKKQpgYGAKCi0tLQoKIyBIZXIgZMO2a8O8bWFuxLFuIHNvbnVuYSBrdWxsYW5kxLHEn8SxbsSxeiBrw7x0w7xwaGFuZWxlciBpw6dpbiBhdMSxZiB5YXpkxLFyYWJpbGlyc2luaXoKCmBgYAp7cn0KY2l0YXRpb24oKQpgYGAKCi0tLQoKIyMgTGlicmFyaWVzIFVzZWQgIAoKYGBge3IgbGlicmFyeSBjaXRhdGlvbiwgZWNobz1UUlVFfQpjaXRhdGlvbigpCmBgYAoKLS0tCgojIyBCdSBvdHVydW1hIHNwZXNpZmlrIGt1bGxhbsSxbGFuIHBha2V0bGVyICAKCmBgYHtyIGxpYnJhcnkgY2l0YXRpb24gYXMgcmVwb3J0LCBlY2hvPVRSVUUsIHJlc3VsdHM9J2FzaXMnfQpyZXBvcnQ6OmNpdGVfcGFja2FnZXMoc2Vzc2lvbiA9IHNlc3Npb25JbmZvKCkpCmBgYAoKCi0tLQoKIyMgVGVrIHRlayBwYWtldCBhdMSxZmxhcsSxCgoKYGBgCntyIGxpYnJhcnkgY2l0YXRpb25zfQpjaXRhdGlvbigidGlkeXZlcnNlIikKY2l0YXRpb24oInJlYWR4bCIpCmNpdGF0aW9uKCJqYW5pdG9yIikKY2l0YXRpb24oInJlcG9ydCIpCmNpdGF0aW9uKCJmaW5hbGZpdCIpCmNpdGF0aW9uKCJnZ3N0YXRwbG90IikKYGBgCgoKLS0tCgojIyBKYW1vdmkgdmUgUiBpw6dpbiBhdMSxZiDDtnJuZcSfaQoKLSBUaGUgamFtb3ZpIHByb2plY3QgKDIwMTkpLiBqYW1vdmkuIChWZXJzaW9uIDAuOSkgW0NvbXB1dGVyIFNvZnR3YXJlXS4gUmV0cmlldmVkIGZyb20gaHR0cHM6Ly93d3cuamFtb3ZpLm9yZy4KCi0gUiBDb3JlIFRlYW0gKDIwMTgpLiBSOiBBIExhbmd1YWdlIGFuZCBlbnZpb25tZW50IGZvciBzdGF0aXN0aWNhbCBjb21wdXRpbmcuIFtDb21wdXRlciBzb2Z0d2FyZV0uIFJldHJpZXZlZCBmcm9tIGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnLy4KCi0gRm94LCBKLiwgJiBXZWlzYmVyZywgUy4gKDIwMTgpLiBjYXI6IENvbXBhbmlvbiB0byBBcHBsaWVkIFJlZ3Jlc3Npb24uIFtSIHBhY2thZ2VdLiBSZXRyaWV2ZWQgZnJvbSBodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy9wYWNrYWdlPWNhci4KCgoKLS0tCgojIEhlciBkw7Zrw7xtYW7EsW4gc29udW5hIG90dXJ1bSBkZXRheWxhcsSxbsSxesSxIHlhemTEsXJhYmlsaXJzaW5peiAgCgpgYGAKe3Igc2Vzc2lvbiBpbmZvLCBlY2hvPVRSVUV9CnNlc3Npb25JbmZvKCkKYGBgCgotLS0KCiMjIFNlc3Npb24gSW5mbwoKYGBge3Igc2Vzc2lvbiBpbmZvLCBlY2hvPVRSVUV9CnNlc3Npb25JbmZvKCkKYGBgCgotLS0KCiMgU29ucmFraSBLb251bGFyCgotIFJTdHVkaW8gaWxlIEdpdEh1YiBrdWxsYW7EsW3EsQotIC4uLgoKLS0tCgojIMOWbmVyaWxlbiBLYXluYWtsYXIKCi0gW1JlcHJvZHVjaWJsZSBUZW1wbGF0ZXMgZm9yIEFuYWx5c2lzIGFuZCBEaXNzZW1pbmF0aW9uXShodHRwczovL3d3dy5jb3Vyc2VyYS5vcmcvbGVhcm4vcmVwcm9kdWNpYmxlLXRlbXBsYXRlcy1hbmFseXNpcy9ob21lL2luZm8pCgotIFtIYXBweSBHaXQgYW5kIEdpdEh1YiBmb3IgdGhlIHVzZVJdKGh0dHBzOi8vaGFwcHlnaXR3aXRoci5jb20vKQoKCgoKCi0tLQoKIyBTdW51bSBMaW5rbGVyaQoKaHR0cHM6Ly9zYmFsY2kuZ2l0aHViLmlvL015UkNvZGVzRm9yRGF0YUFuYWx5c2lzL1ItTWFya2Rvd24ubmIuaHRtbApodHRwczovL3NiYWxjaS5naXRodWIuaW8vTXlSQ29kZXNGb3JEYXRhQW5hbHlzaXMvUi1NYXJrZG93bi5odG1sCgpodHRwczovL2Zvcm1zLmdsZS9VcUdKQmlBakI4dUxQUm9uOAoKLS0tCgojIEdlcmkgQmlsZGlyaW0KCi0gR2VyaSBiaWxkaXJpbSBpw6dpbiB0xLFrbGF5xLFuxLF6OiBfW0dlcmkgYmlsZGlyaW0gZm9ybXVdKGh0dHBzOi8vZ29vLmdsL2Zvcm1zL1lqR1o1REhndFBsUjFSbkIzKV8KCgotLS0KCjxzY3JpcHQgaWQ9ImRzcS1jb3VudC1zY3IiIHNyYz0iLy9odHRwcy1zYmFsY2ktZ2l0aHViLWlvLmRpc3F1cy5jb20vY291bnQuanMiIGFzeW5jPjwvc2NyaXB0PgoKPGRpdiBpZD0iZGlzcXVzX3RocmVhZCI+PC9kaXY+CjxzY3JpcHQ+CgovKioKKiAgUkVDT01NRU5ERUQgQ09ORklHVVJBVElPTiBWQVJJQUJMRVM6IEVESVQgQU5EIFVOQ09NTUVOVCBUSEUgU0VDVElPTiBCRUxPVyBUTyBJTlNFUlQgRFlOQU1JQyBWQUxVRVMgRlJPTSBZT1VSIFBMQVRGT1JNIE9SIENNUy4KKiAgTEVBUk4gV0hZIERFRklOSU5HIFRIRVNFIFZBUklBQkxFUyBJUyBJTVBPUlRBTlQ6IGh0dHBzOi8vZGlzcXVzLmNvbS9hZG1pbi91bml2ZXJzYWxjb2RlLyNjb25maWd1cmF0aW9uLXZhcmlhYmxlcyovCi8qCnZhciBkaXNxdXNfY29uZmlnID0gZnVuY3Rpb24gKCkgewp0aGlzLnBhZ2UudXJsID0gUEFHRV9VUkw7ICAvLyBSZXBsYWNlIFBBR0VfVVJMIHdpdGggeW91ciBwYWdlJ3MgY2Fub25pY2FsIFVSTCB2YXJpYWJsZQp0aGlzLnBhZ2UuaWRlbnRpZmllciA9IFBBR0VfSURFTlRJRklFUjsgLy8gUmVwbGFjZSBQQUdFX0lERU5USUZJRVIgd2l0aCB5b3VyIHBhZ2UncyB1bmlxdWUgaWRlbnRpZmllciB2YXJpYWJsZQp9OwoqLwooZnVuY3Rpb24oKSB7IC8vIERPTidUIEVESVQgQkVMT1cgVEhJUyBMSU5FCnZhciBkID0gZG9jdW1lbnQsIHMgPSBkLmNyZWF0ZUVsZW1lbnQoJ3NjcmlwdCcpOwpzLnNyYyA9ICdodHRwczovL2h0dHBzLXNiYWxjaS1naXRodWItaW8uZGlzcXVzLmNvbS9lbWJlZC5qcyc7CnMuc2V0QXR0cmlidXRlKCdkYXRhLXRpbWVzdGFtcCcsICtuZXcgRGF0ZSgpKTsKKGQuaGVhZCB8fCBkLmJvZHkpLmFwcGVuZENoaWxkKHMpOwp9KSgpOwo8L3NjcmlwdD4KPG5vc2NyaXB0PlBsZWFzZSBlbmFibGUgSmF2YVNjcmlwdCB0byB2aWV3IHRoZSA8YSBocmVmPSJodHRwczovL2Rpc3F1cy5jb20vP3JlZl9ub3NjcmlwdCI+Y29tbWVudHMgcG93ZXJlZCBieSBEaXNxdXMuPC9hPjwvbm9zY3JpcHQ+CgotLS0KCiMgxLBsZXRpxZ9pbSAgCgpDb21wbGV0ZWQgb24gYHIgU3lzLkRhdGUoKWAuICAKClNlcmRhciBCYWxjaSwgTUQsIFBhdGhvbG9naXN0ICAKZHJzZXJkYXJiYWxjaUBnbWFpbC5jb20gIAoKaHR0cHM6Ly9ycHVicy5jb20vc2JhbGNpL0NWICAgCmh0dHBzOi8vc2JhbGNpLmdpdGh1Yi5pby8gIApodHRwczovL2dpdGh1Yi5jb20vc2JhbGNpICAKaHR0cHM6Ly90d2l0dGVyLmNvbS9zZXJkYXJiYWxjaQoKCi0tLQoKICAgCgoKCi0tLQoKCiMgT3RoZXIgTGlua3MKCgpodHRwczovL2FuZHJld2J0cmFuLmdpdGh1Yi5pby9OSUNBUi8yMDE4L3dvcmtmbG93L2RvY3MvMDItcm1hcmtkb3duLmh0bWwKCi0gVHJvdWJsZXNob290aW5nIGluIFIgTWFya2Rvd24KCmh0dHBzOi8vc21pdGhjb2xsZWdlLXNkcy5naXRodWIuaW8vc2RzLXB1YmxpYy9ybWFya2Rvd25fcHJvYmxlbXMuaHRtbAoKCmh0dHA6Ly9rYnJvbWFuLm9yZy9rbml0cl9rbnV0c2hlbGwvcGFnZXMvUm1hcmtkb3duLmh0bWwKCmh0dHBzOi8va2Jyb21hbi5vcmcva25pdHJfa251dHNoZWxsL3BhZ2VzL292ZXJ2aWV3Lmh0bWwKCmh0dHBzOi8va2Jyb21hbi5vcmcva25pdHJfa251dHNoZWxsL3BhZ2VzL1JtYXJrZG93bi5odG1sCgpodHRwczovL2ticm9tYW4ub3JnL2tuaXRyX2tudXRzaGVsbC9wYWdlcy9tYXJrZG93bi5odG1sCgoKaHR0cHM6Ly9vbnA0LmNvbS8KCgoKYGBgCmNzdiB7aGVhZGVyczogdHJ1ZSwgdGl0bGU6ICIqKkRyYXdpbmcgVGFibGVzIEluIE1hcmtkb3duKioifQpOYW1lLCBTdXJuYW1lLCBLbm93biBBcywgQWdlCk1hcmNlbG8sIERhdmlkLCBjb2xkemVyYSwgMjIKT2xla3NhbmRyLCBLb3N0eWxpZXYsIHMxbXBsZSwgMTkKTmlrb2xhLCBLb3ZhxI0sIE5pS28sIDIwClJpY2hhcmQsIFBhcGlsbG9uLCBzaG94LCAyNQpOaWNvbGFpLCBSZWVkdHosIGRldjFjZSwgMjEKYGBgCgpgYGAKe3Bnbn0KW0V2ZW50ICJCbGVkLVphZ3JlYi1CZWxncmFkZSBDYW5kaWRhdGVzIl0KW1NpdGUgIkJsZWQsIFphZ3JlYiAmIEJlbGdyYWRlIFlVRyJdCltEYXRlICIxOTU5LjEwLjExIl0KW1JvdW5kICIyMCJdCltSZXN1bHQgIjEtMCJdCltXaGl0ZSAiTWlraGFpbCBUYWwiXQpbQmxhY2sgIlJvYmVydCBKYW1lcyBGaXNjaGVyIl0KCjEuIGQ0IE5mNiAyLiBjNCBnNiAzLiBOYzMgQmc3IDQuIGU0IGQ2IDUuCkJlMiBPLU8gNi4gTmYzIGU1IDcuIGQ1IE5iZDcgOC4gQmc1IGg2IDkuCkJoNCBhNiAxMC4gTy1PIFFlOCAxMS4gTmQyIE5oNyAxMi4gYjQgQmY2CjEzLiBCeGY2IE5oeGY2IDE0LiBOYjMgUWU3IDE1LiBRZDIgS2g3IDE2LgpRZTMgTmc4IDE3LiBjNSBmNSAxOC4gZXhmNSBneGY1IDE5LiBmNCBleGY0CjIwLiBReGY0IGR4YzUgMjEuIEJkMyBjeGI0IDIyLiBSYWUxIFFmNiAyMy4KUmU2IFF4YzMgMjQuIEJ4ZjUrIFJ4ZjUgMjUuIFF4ZjUrIEtoOCAyNi4KUmYzIFFiMiAyNy4gUmU4IE5mNiAyOC4gUXhmNisgUXhmNiAyOS4gUnhmNgpLZzcgMzAuIFJmZjggTmU3IDMxLiBOYTUgaDUgMzIuIGg0IFJiOCAzMy4KTmM0IGI1IDM0LiBOZTUgMS0wCmBgYAoKCi0gS2VlcGluZyBDcmVkZW50aWFscyBTZWNyZXQgd2l0aCBLZXlyaW5ncyBpbiBSCgpodHRwczovL3JhczQ0LmdpdGh1Yi5pby9ibG9nLzIwMTkvMDEvMTkva2VlcGluZy1jcmVkZW50aWFscy1zZWNyZXQtd2l0aC1rZXlyaW5ncy1pbi1yLmh0bWwKCi0gSG93IHRvIGJ1aWxkIGEgd2Vic2l0ZSB3aXRoIEJsb2dkb3duIGluIFIKCmh0dHA6Ly93d3cuc3RvcnliZW5jaC5vcmcvaG93LXRvLWJ1aWxkLWEtd2Vic2l0ZS13aXRoLWJsb2dkb3duLWluLXIvCg==